<template>
  <div class="hud-container">
    <div class="opening-animation" ref="openingAnimation"></div>
    <span class="hud-trace-container" v-show="showHud">
      <div class="hud-trace-container-padding top"></div>
      <div class="hud-trace">
        <div class="hud-trace-padding" ref="hudTracePadding"></div>
        <div>
          <div class="hud-trace-cursor">
            <span class="hud-trace-cursor-icon"></span>
          </div>
        </div>
      </div>
      <div class="hud-trace-container-padding bottom"></div>
    </span>
    <span class="hud" ref="hud" v-show="showHud">
      <div class="hud-border top">
        <div class="hud-angle left top"></div>
        <div class="hud-angle right top"></div>
        <div class="hud-border shadow top">
          <div class="hud-angle shadow left top"></div>
          <div class="hud-angle shadow right top"></div>
        </div>
      </div>
      <!-- 动态加载的内容 start -->
      <div class="hud-body" ref="hudBody">
        <DynamicComponent
          ref="hudBodyContent"
          :componentName="componentName"
          :importPath="importPath"
          :componentObj="componentObj"
        ></DynamicComponent>
      </div>
      <!-- 动态加载的内容 end -->
      <div class="hud-border bottom">
        <div class="hud-angle left bottom">
          <!-- <div class="hud-content-length-view"></div> -->
        </div>
        <div class="hud-angle right bottom"></div>
        <div class="hud-border shadow bottom">
          <div class="hud-angle shadow left bottom"></div>
          <div class="hud-angle shadow right bottom"></div>
        </div>
      </div>
    </span>
  </div>
</template>

<script>
import DynamicComponent from './DynamicComponent.vue'
import gsap from 'gsap'
export default {
  name: 'HudSub',
  components: { DynamicComponent },
  props: {
    componentName: String,
    importPath: String,
    componentObj: Object
  },
  data () {
    return {
      spreadAnimation: null,
      showHud: true,
      scrollAnimationReady: true,
      cursorAbsoluteTop: -1
    }
  },
  mounted () {
    // 窗口重绘事件
    window.addEventListener('resize', this.updateCursorHightFrequency, true)
    // 编辑区的滚动事件
    this.$refs.hudBody.addEventListener(
      'scroll',
      this.updateCursorHightFrequency,
      true
    )
    // 光标选区修改事件
    document.addEventListener(
      'selectionchange',
      this.selectionChangeHandle,
      true
    )
    // 开场动画
    this.openingAnimation()
  },
  destroyed () {
    window.removeEventListener('resize', this.updateCursorHightFrequency, true)
    document.removeEventListener(
      'scroll',
      this.updateCursorHightFrequency,
      true
    )
    document.removeEventListener(
      'selectionchange',
      this.selectionChangeHandle,
      true
    )
  },
  methods: {
    // 开场动画
    openingAnimation () {
      let self = this
      self.showHud = false
      if (!this.spreadAnimation) {
        this.spreadAnimation = gsap
          .timeline()
          // 展开动画
          .to(this.$refs.hud, {
            startAt: { y: '50vh', height: 0 },
            y: '0vh',
            height: '100%',
            duration: 0.6,
            onStart () {
              self.showHud = true
            }
          })
      }
      this.spreadAnimation.play()
    },
    // 退出动画
    escapeAnimation () {
      if (this.spreadAnimation) {
        return gsap
          .timeline()
          .add(this.spreadAnimation.reverse())
          .timeScale(1.5)
      }
      return null
    },
    updateCursorHightFrequency () {
      if (this.cursorAbsoluteTop >= 0 && this.scrollAnimationReady) {
        this.scrollAnimationReady = false
        window.requestAnimationFrame(() => {
          // 更新游标
          this.updateCursor(this.cursorAbsoluteTop, this.$refs.hudBody)
          this.scrollAnimationReady = true
        })
      }
    },
    selectionChangeHandle () {
      let selection = window.getSelection()
      let offset = selection.focusOffset
      let textEl = selection.focusNode
      if (!this.$refs.hudBody.contains(textEl)) {
        return
      }
      let textContent = textEl.nodeValue
      let probeEl = document.createElement('span')
      probeEl.innerHTML = '&zwnj;'
      // 插入定位用的节点
      if (offset === 0) {
        textEl.before(probeEl)
      } else if (offset === textContent.length) {
        textEl.after(probeEl)
      } else {
        textEl.splitText(offset)
        textEl.after(probeEl)
      }
      // 获取主体的高度
      let scrollEl = this.$refs.hudBody
      let scrollElPosInfo = scrollEl.getBoundingClientRect()
      // 探针的位置信息
      let probeElPosInfo = probeEl.getBoundingClientRect()
      let probeRelativeTop =
        (probeElPosInfo.top + probeElPosInfo.bottom) / 2 - scrollElPosInfo.top
      let probeAbsoluteTop = scrollEl.scrollTop + probeRelativeTop
      this.cursorAbsoluteTop = probeAbsoluteTop
      // 更新游标
      this.updateCursor(probeAbsoluteTop, this.$refs.hudBody)
      // 删除节点
      textEl.parentElement.removeChild(probeEl)
    },
    // 游标的相关操作
    updateCursor (cursorAbsoluteTop, scrollEl) {
      // 移动游标到指定高度
      let cursorRelativePctTop =
        ((cursorAbsoluteTop - scrollEl.scrollTop) / scrollEl.clientHeight) * 100
      cursorRelativePctTop =
        cursorRelativePctTop < 0
          ? 0
          : cursorRelativePctTop > 100
            ? 100
            : cursorRelativePctTop
      gsap.to(this.$refs.hudTracePadding, {
        overwrite: true,
        height: cursorRelativePctTop + '%'
      })
    }
  }
}
</script>

<style scoped>
.opening-animation {
  display: none;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  width: 20px;
  height: 30px;
  background-color: rgba(0, 0, 0, 0.4);
}
.opening-animation::after {
  content: '';
  position: absolute;
  transform: translate(5px, 4px);
  width: 20px;
  height: 30px;
  background-color: rgba(0, 0, 0, 0.1);
}
.hud-container {
  position: relative;
  width: 100%;
  height: 100%;
}
.hud-container::before {
  content: '';
  position: absolute;
  transform: translate(9px, 0);
  top: 0;
  bottom: 0;
  margin: auto;
  display: block;
  width: 2.5px;
  height: 20px;
  background-color: rgba(0, 0, 0, 0.06);
}
.hud-container::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  display: block;
  width: 20px;
  height: 2.5px;
  background-color: rgba(0, 0, 0, 0.06);
}
.hud-trace-container {
  position: absolute;
  display: inline-flex;
  left: calc(100% - 10px);
  flex-direction: column;
  width: 0px;
  height: 100%;
}
.hud-trace-container-padding {
  height: 0px;
}
.hud-trace {
  flex: auto;
  height: 100%;
  width: 0px;
}
.hud-trace-padding {
  height: 50%;
}
.hud-trace-cursor {
  position: absolute;
  left: 100%;
  transform: translate(0, -50%);
}
.hud-trace-cursor-icon {
  display: inline-block;
  width: 0;
  height: 0;
  border-top: 10px solid transparent;
  border-right: 10px solid rgba(0, 0, 0, 0.05);
  border-bottom: 10px solid transparent;
}
.hud {
  position: relative;
  float: right;
  display: flex;
  flex-direction: column;
  word-wrap: break-word;
  width: 100%;
  height: 100%;
}
.hud-body {
  flex: 1;
  margin: 0px 20px 15px 30px;
  overflow-y: scroll;
}
.hud-body::-webkit-scrollbar {
  display: none;
}
.hud-border {
  position: relative;
  height: 0px;
  width: 100%;
}
.hud-angle {
  position: absolute;
  display: inline-block;
  border: 3px solid #b2b2b2;
  width: 10px;
  height: 17px;
}
.hud-angle.left.top {
  border-right-width: 0px;
  border-left-width: 0px;
  border-bottom-width: 0px;
}
.hud-angle.right.top {
  right: 0;
  border-left-width: 0px;
  border-right-width: 0px;
  border-bottom-width: 0px;
}
.hud-angle.left.bottom {
  bottom: 0px;
  border-right-width: 0px;
  border-left-width: 0px;
  border-top-width: 0px;
}
.hud-angle.right.bottom {
  right: 0;
  bottom: 0px;
  border-left-width: 0px;
  border-right-width: 0px;
  border-top-width: 0px;
}
.shadow {
  z-index: -1;
  position: absolute;
  border-color: rgba(0, 0, 0, 0.06);
}
.hud-border.shadow {
  transform: translate(8px, 10px);
  width: 100%;
  height: 0;
}
.hud-border.shadow.bottom {
  height: 1px;
  transform: translate(8px, -7px);
  background-color: rgba(0, 0, 0, 0.03);
}
.trace-cursor {
  border: 1px solid rgba(251, 193, 5, 0.7);
  width: 5px;
  height: 5px;
}
</style>
